package com.traffic.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.traffic.annotation.NeedLogin;
import com.traffic.annotation.Power;
import com.traffic.constant.Const;
import com.traffic.constant.Status;
import com.traffic.entity.PageResult;
import com.traffic.entity.Rank;
import com.traffic.entity.User;
import com.traffic.entity.UserInfo;
import com.traffic.exception.BaseException;
import com.traffic.mapper.UserInfoMapper;
import com.traffic.mapper.UserMapper;
import com.traffic.model.ApiResponse;
import com.traffic.model.PushUser;
import com.traffic.service.RankService;
import com.traffic.service.SmsService;
import com.traffic.service.UserInfoService;
import com.traffic.service.UserService;
import com.traffic.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


/**
 * Created by IntelliJ IDEA.
 * User: KingRainGrey
 * Date: 2020/9/3
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private SmsService smsService;

    @Autowired
    private RankService rankService;



    /**
     * 用户登录或是注册
     * @param phone
     * @return
     */
    @Override
    @Transactional
    public String loginOrRegister(String phone) {

        // 验证通过后 获取phone
        // String phone = IdUtil.fastSimpleUUID().substring(0, 11);

        String token = null;
        // 验证该号码是否已经注册
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("account", phone);
        User user = userMapper.selectOne(wrapper);
        // 号码未注册 账户是空的  或者账户已经被删除过了 重新注册
        if (ObjectUtil.isNull(user) || (ObjectUtil.isNotNull(user) && user.getStatus() == -1)) {
            // 没有注册
            User save = User.builder().account(phone).status(1).type(0).lastLoginTime(new DateTime()).registrationid("").role(new Long(6)).build();
            int result = userMapper.insert(save);
            if (result > 0) {
                // 注册成功
                // 初始化用户信息
                String uuid = IdUtil.fastSimpleUUID();
                String tempNickName = uuid.substring(0,uuid.length() >= Const.NICK_NAME_LENGTH ? Const.NICK_NAME_LENGTH : uuid.length());
                UserInfo userInfo = UserInfo.builder().userId(save.getId()).phone(save.getAccount()).nickName(tempNickName).headImg(new Long(109)).build();
                userInfoService.save(userInfo);

                Rank newrank = Rank.builder().userId(save.getId()).afternoonTime(1.0).allTime(3.0).eveningTime(1.0).hisAcc(0.0)
                        .hisMileage(0.1).hisVel(0.0).level(0).maxAcc(0.0).maxNAcc(0.0).morningTime(1.0).score(0.0).stationarity(0.0).hisNAcc(0.0).statimes(1).build();
                boolean res = rankService.save(newrank);

                // 生成token
                token = jwtUtil.sign(save);
                stringRedisTemplate.opsForValue().set(Const.TOKEN_PREFIX + save.getAccount(), token);
                return token;
            } else {
                throw new BaseException(Status.UNKNOWN_ERROR);
            }
        } else {
            // 已经注册
            // 检查redis是否已有token
            String oldToken = stringRedisTemplate.opsForValue().get(Const.TOKEN_PREFIX + user.getAccount());
            if (StrUtil.isNotEmpty(oldToken)) {
                // 库里已有token 用户没有注销登录 token没有过期
                // 清除旧的token
                stringRedisTemplate.delete(Const.TOKEN_PREFIX + user.getAccount());
            }
            // 更新最后一次登录时间
            user.setLastLoginTime(new DateTime());
            userMapper.updateById(user);
            // 重新生成token
            token = JwtUtil.sign(user);
            stringRedisTemplate.opsForValue().set(Const.TOKEN_PREFIX + user.getAccount(), token);
            return token;
        }
    }

    /**
     * 用户注销 清空token
     * @param account
     * @return
     */
    @Override
    public boolean logout(String account) {

        if (jwtUtil.check(account)) {
            stringRedisTemplate.delete(Const.TOKEN_PREFIX + account);
            return true;
        }
        throw new BaseException(Status.TOKEN_ERROR);
    }

    /**
     * 判断用户是否登录 有无token
     * @param account
     * @return
     */
    @Override
    public boolean isLogin(String account) {
        String oldToken = stringRedisTemplate.opsForValue().get(Const.TOKEN_PREFIX + account);
        if (StrUtil.isNotEmpty(oldToken)) {
            // 库里已有token 用户没有注销登录 token没有过期
            // 清除旧的token
            return true;
        }
        return false;
//        if (jwtUtil.check(account)) {
//            return true;
//        }
//        return false;
    }

    /**
     * 管理员直接创建用户
     * @param userParam
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_ADD)
    @Transactional
    public User createUser(Map<String, Object> userParam) {
        String param[] = new String[] {"nickName", "city", "birthday", "sex", "profile", "phone"};
        List<String> paramList = CollUtil.newArrayList(param);
        if (!paramList.containsAll(CollUtil.newArrayList(userParam.keySet().toArray()))) {
            throw new BaseException(Status.PARAM_ERROR);
        }
        if (!userParam.containsKey("phone")) {
            throw new BaseException(Status.PARAM_MISS);
        }
        UserInfo userInfo = new UserInfo();
        BeanUtil.copyProperties(userParam, userInfo, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        User user = User.builder().account(userParam.get("phone").toString()).status(Const.ACCOUNT_NORMAL_TAG).build();
        int userResult = userMapper.insert(user);
        if (userResult > 0) {
            userInfo.setUserId(user.getId());
            boolean userInfoResult = userInfoService.save(userInfo);
            if (userInfoResult) {
                return user;
            }
        }
        return null;
    }

    /**
     * 通过userid 查询user
     * @param id
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_QUERY)
    public PageResult queryUserById(Long id) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        User user = userMapper.selectOne(wrapper);
        Integer total = userMapper.selectCount(wrapper);

        return PageResult.builder().user(user).total(total).build();
    }

    /**
     * 通过phone 查询user
     * @param phone
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_QUERY)
    public PageResult queryUserByPhone(String phone) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("account", phone);
        User user = userMapper.selectOne(wrapper);
        Integer total = userMapper.selectCount(wrapper);

        return PageResult.builder().user(user).total(total).build();
    }

    /**
     * 查询user 分页查询
     * @param currentPage
     * @param pageSize
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_QUERY)
    public PageResult queryUserList(Integer currentPage, Integer pageSize) {
        IPage<User> userPage = new Page<>(currentPage, pageSize);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        IPage<User> page = userMapper.selectPage(userPage, wrapper);
        Integer total = userMapper.selectCount(wrapper);
        PageResult result = PageResult.builder().list(page.getRecords()).total(total).build();
        return result;
    }

    /**
     * 查询user 带条件的分页查询
     * @param param
     * @param currentPage
     * @param pageSize
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_QUERY)
    public PageResult queryUserList(Map<String, Object> param, Integer currentPage, Integer pageSize) {

        if (param.get("sex") == null && param.get("city") == null
                && param.get("rank") == null && param.get("age_start") == null
                    && param.get("age_end") == null && param.get("role") == null
                        && param.get("create_time_start") == null && param.get("create_time_end") == null
                            && param.get("login_time_start") == null && param.get("login_time_end") == null) {


            return queryUserList(currentPage, pageSize);
        }



        QueryWrapper<UserInfo> infoWrapper = new QueryWrapper<>();
        /**
         * param中可有的查询条件  性别 地区 年龄 注册时间 登录时间  用户类型  等级
         */
        /**
         * 0-男
         * 1-女
         */
        if (ObjectUtil.isNotNull(param.get("sex"))) {
            if(StrUtil.isNotEmpty(param.get("sex").toString())) {
                infoWrapper.eq("sex", Integer.parseInt(param.get("sex").toString()));
            }
        }
        if (ObjectUtil.isNotNull(param.get("city"))) {
            if (StrUtil.isNotEmpty(param.get("city").toString())) {
                String cityString = param.get("city").toString();
                String[] list = cityString.split("/");
                String tag = null;
                if (list.length >= 2) {
                    tag = list[1];
                }else if (list.length >= 1 && list.length < 2) {
                    tag = list[0];
                }
                infoWrapper.like("city", "%" + tag + "%");
            }
        }
        if (ObjectUtil.isNotNull(param.get("rank"))) {
            if (StrUtil.isNotEmpty(param.get("rank").toString())) {
                infoWrapper.eq("rank", Integer.parseInt(param.get("rank").toString()));
            }
        }
        infoWrapper.orderByDesc("id");
        List<UserInfo> userInfoList = userInfoMapper.selectList(infoWrapper);
        List<Long> result = new ArrayList<>();
        userInfoList.forEach(info -> {
            result.add(info.getUserId());
        });

        if (ObjectUtil.isNotNull(param.get("age_start")) && ObjectUtil.isNotNull(param.get("age_end"))) {
            if (StrUtil.isNotEmpty(param.get("age_start").toString()) && StrUtil.isNotEmpty(param.get("age_end").toString())) {
                result.clear();
                Integer start = Integer.parseInt(param.get("age_start").toString());
                Integer end = Integer.parseInt(param.get("age_end").toString());
                userInfoList.stream().forEach(info -> {
                    if(ObjectUtil.isNotNull(info.getBirthday())) {
                        Integer age = DateUtil.ageOfNow(info.getBirthday());
                        if (age >= start && age <= end) {
                            result.add(info.getUserId());
                        }
                    }
                });
            }
        }

        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(param.get("role"))) {
            if (StrUtil.isNotEmpty(param.get("role").toString())) {
                userWrapper.eq("role", Integer.parseInt(param.get("role").toString()));
            }
        }
        if (ObjectUtil.isNotNull(param.get("create_time_start")) && ObjectUtil.isNotNull(param.get("create_time_end"))) {
            if (StrUtil.isNotEmpty(param.get("create_time_start").toString()) && StrUtil.isNotEmpty(param.get("create_time_end").toString())) {
                userWrapper.ge("create_time", param.get("create_time_start"));// 大于开始时间
                userWrapper.le("create_time", param.get("create_time_end"));// 小于结束结束
            }
        }
        if (ObjectUtil.isNotNull(param.get("login_time_start")) && ObjectUtil.isNotNull(param.get("login_time_end"))) {
            if (StrUtil.isNotEmpty(param.get("login_time_start").toString()) &&
                    StrUtil.isNotEmpty(param.get("login_time_end").toString())) {
                userWrapper.ge("last_login_time", param.get("login_time_start"));
                userWrapper.le("last_login_time", param.get("login_time_end"));
            }
        }
        // 没有数据
        if (result.size() > 0) {
            userWrapper.in("id", result);
        }else {
            PageResult allResult = PageResult.builder().list(null).total(0).build();
            return allResult;
        }

        IPage<User> userPage = new Page<>(currentPage, pageSize);
        userWrapper.orderByDesc("id");

        IPage<User> page = userMapper.selectPage(userPage, userWrapper);
        Integer total = userMapper.selectCount(userWrapper);
        PageResult allResult = PageResult.builder().list(page.getRecords()).total(total).build();

        return allResult;
    }

    /**
     * 冻结账户 若有token清除
     * @param id
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_EDIT)
    public User frozen(Long id) {
        User user = userMapper.selectById(id);
        if (ObjectUtil.isNotNull(user)) {
            user.setStatus(Const.ACCOUNT_FROZEN_TAG);
            userMapper.updateById(user);
            /**
             * 清除token
             */
            String oldToken = stringRedisTemplate.opsForValue().get(Const.TOKEN_PREFIX + user.getAccount());
            if (StrUtil.isNotEmpty(oldToken)) {
                stringRedisTemplate.delete(Const.TOKEN_PREFIX + user.getAccount());
            }
        }
        return user;
    }

    /**
     * 解冻账户
     * @param id
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_EDIT)
    public User thaw(Long id) {
        User user = userMapper.selectById(id);
        if (ObjectUtil.isNotNull(user)) {
            user.setStatus(Const.ACCOUNT_NORMAL_TAG);
            userMapper.updateById(user);
        }
        return user;
    }

    /**
     * 删除账户
     * @param id
     * @return
     */
    @Override
    @Power(authority = Const.AUTH_DELETE)
    @Transactional
    public Boolean deleteAccount(Long id) {
        /**
         * 同时删除用户信息
         */
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", id);
        UserInfo userInfo = userInfoMapper.selectOne(wrapper);
        if (ObjectUtil.isNotNull(userInfo)) {
            userInfoMapper.deleteById(userInfo.getId());
        }
        User user = userMapper.selectById(id);
        if (ObjectUtil.isNotNull(user)) {
            userMapper.deleteById(user.getId());
        }
        return true;
    }

    /**
     * 用户修改手机号 先短信验证
     * 修改手机号 需要重新登录
     * @param oldPhone
     * @param newPhone
     * @return
     */
    //@NeedLogin
    @Override
    @Transactional
    public Boolean editPhone(String oldPhone, String newPhone) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("account", oldPhone);
        User user = userMapper.selectOne(wrapper);
        if (ObjectUtil.isNotNull(user)) {
            Long userId = user.getId();
            QueryWrapper<UserInfo> wrapperInfo = new QueryWrapper<>();
            wrapperInfo.eq("user_id", userId);
            UserInfo userInfo = userInfoMapper.selectOne(wrapperInfo);
            if (ObjectUtil.isNotNull(userInfo)) {
                try {
                    user.setAccount(newPhone);
                    userInfo.setPhone(newPhone);
                    userMapper.updateById(user);
                    userInfoMapper.updateById(userInfo);
                }catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
                // 修改成功后 对登录token进行处理
                // 已经注册
                // 检查redis是否已有token
                String oldToken = stringRedisTemplate.opsForValue().get(Const.TOKEN_PREFIX + oldPhone);
                if (StrUtil.isNotEmpty(oldToken)) {
                    // 库里已有token 用户没有注销登录 token没有过期
                    // 清除旧的token
                    stringRedisTemplate.delete(Const.TOKEN_PREFIX + oldPhone);
                }
                // 更新最后一次登录时间
                user.setLastLoginTime(new DateTime());
                userMapper.updateById(user);
                // 重新生成token
                String token = JwtUtil.sign(user);
                stringRedisTemplate.opsForValue().set(Const.TOKEN_PREFIX + newPhone, oldToken);
                return true;
            }
        }
        return false;
    }


    /**
     * 用手机号 查询userid
     *
     * @param phone
     * @return
     */

    @Override
    public Object getUserId(String phone) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        Object userid = userMapper.selectObjs(wrapper.select("id").eq("account",phone));
        return userid;
    }


    @Override
    public List<PushUser> getuserRID(String phonenick) {

        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        List<UserInfo> puser = userInfoMapper.selectList(wrapper.eq("phone",phonenick).or().eq("nick_name",phonenick));

        List<PushUser> pushUsers = new ArrayList<>();
        for (UserInfo u: puser) {
            PushUser push = new PushUser();
            push.setNick_name(u.getNickName());
            push.setPhone(u.getPhone());

            User temp = userMapper.selectById(u.getUserId());

            push.setRegistrationid(temp.getRegistrationid());
            pushUsers.add(push);
        }


        return pushUsers;
    }

    /**
     * 用户自己删除自己的账户  状态设置为-1 逻辑删除 清除登录token
     * @param id
     * @return
     */
    @Override
    @NeedLogin
    @Transactional
    public Boolean userDeleteOwn(Long id) {
//        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
//        wrapper.eq("user_id", id);
//        UserInfo userInfo = userInfoMapper.selectOne(wrapper);
//        if (ObjectUtil.isNotNull(userInfo)) {
//            userInfoMapper.deleteById(userInfo.getId());
//        }
        User user = userMapper.selectById(id);
        if (ObjectUtil.isNotNull(user)) {
            user.setStatus(-1);
            //userMapper.deleteById(user.getId());
            userMapper.updateById(user);
            String oldToken = stringRedisTemplate.opsForValue().get(Const.TOKEN_PREFIX + user.getAccount());
            if (StrUtil.isNotEmpty(oldToken)) {
                // 库里已有token 用户没有注销登录 token没有过期
                // 清除旧的token
                stringRedisTemplate.delete(Const.TOKEN_PREFIX + user.getAccount());
            }
            return true;
        }

        return false;
    }
}
